﻿#region Copyright 
/*-------------------------------------------------------------------------
* 命名空间名称/文件名:    SSPivot.AspNetCore.Filter/MvcExceptionHandleFilterAttribute 
* CLR版本:     4.0.30319.42000
* 机器名称:    DESKTOP-NHMLO8A
* 功 能：       N/A
* 类 名：       MvcExceptionHandleFilterAttribute
* 创建时间：  2025/6/3 17:17:12
* 版本号：      v1.0
* 创建人:        xulong
*-------------------------------------------------------------------------*/
#endregion
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SSPivot.AspNetCore.Abstractions.User;
using SSPivot.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace SSPivot.AspNetCore.Filter
{
    /// <summary>
    /// 异常处理拦截
    /// </summary>
    public class MvcExceptionHandleFilterAttribute : ExceptionFilterAttribute, IExceptionFilter
    {
        #region 变量区域

        private readonly ILogger<MvcExceptionHandleFilterAttribute> _logger;
        private readonly IWebHostEnvironment _env;

        public MvcExceptionHandleFilterAttribute(ILogger<MvcExceptionHandleFilterAttribute> logger
          , IWebHostEnvironment env)
        {
            _logger = logger;
            _env = env;
        }
        #endregion

        #region 接口实现

        /// <summary>
        /// 异常处理
        /// </summary>
        /// <param name="filterContext">上下文</param>
        public override void OnException(ExceptionContext filterContext)
        {
            var exception = filterContext.Exception;
            var eventId = new EventId(exception.HResult);
            var userContext = filterContext.HttpContext.RequestServices.GetService<ICurrentUser>();
            var descriptor = filterContext.ActionDescriptor as ControllerActionDescriptor;
            var methodName = filterContext.HttpContext.Request.Method.ToLower();
            var hostAndPort = filterContext.HttpContext.Request.Host.HasValue ? filterContext.HttpContext.Request.Host.Value : string.Empty;
            var requestUrl = string.Concat(hostAndPort, filterContext.HttpContext.Request.Path);
            var type = string.Concat("https://httpstatuses.com/", filterContext.HttpContext.Response.StatusCode);
            var title = _env.IsDevelopment() ? exception.Message : $"参数错误";
            var detial = _env.IsDevelopment() ? exception.Message : $"系统异常,请联系管理员({eventId})";
            var param = string.Empty;

            param = filterContext.HttpContext.Request.HasFormContentType ? filterContext.HttpContext.Request.Form?.Keys.SerializeJson() : string.Empty;


   
            _logger.LogError(eventId, exception, title);
          
            //判断是webApi还是Mvc的异常
            if (!filterContext.HttpContext.Request.Path.ToString().ToLower().Contains("/api/"))
            {
                filterContext.ExceptionHandled = true;
                filterContext.Result = new BadRequestObjectResult(this.CreateExceptionResponse(filterContext.Exception));
            }
            else
            {
                string actionName = descriptor.ActionName;
                Type controllerType = descriptor.MethodInfo.DeclaringType;
                var method = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
                if (method == null) method = controllerType.GetMethods().Where(e => e.Name.ToLower() == actionName.ToLower()).FirstOrDefault();
                var returnType = method.ReturnType;

                if (returnType.Equals(typeof(JsonResult)))
                {
                    filterContext.ExceptionHandled = true;
                    filterContext.Result = new JsonResult(this.CreateExceptionResponse(filterContext.Exception));
                }
                //else if (returnType.Equals(typeof(JsonResultApi)))
                //{

                //    filterContext.ExceptionHandled = true;
                //    filterContext.Result = new JsonResultApi(this.CreateExceptionResponse(filterContext.Exception));
                //}
                //else if (returnType.Equals(typeof(JsonResultMvc)))
                //{
                //    filterContext.ExceptionHandled = true;
                //    filterContext.Result = new JsonResultMvc(this.CreateExceptionResponse(filterContext.Exception));
                //}
                else
                {
                    filterContext.ExceptionHandled = true;
                    filterContext.Result = new BadRequestObjectResult(this.CreateExceptionResponse(filterContext.Exception));
                }
                //else
                //{
                //    if (returnType.Equals(typeof(IActionResult)) || typeof(IActionResult).IsAssignableFrom(returnType))
                //    {
                //        var pageUrl = string.Empty;
                //        if (actionUrl.ToLower().Contains("/admin"))
                //            pageUrl = ConfigHelper.GetAppSetting("ErrorPageAdmin");
                //        else
                //            pageUrl = ConfigHelper.GetAppSetting("ErrorPage");
                //        if (!string.IsNullOrWhiteSpace(pageUrl)) filterContext.Result = new RedirectResult(pageUrl);
                //    }
                //}
            }
        }
        private IServiceResultBase CreateExceptionResponse(System.Exception exception)
        {
            if (exception.GetType() == typeof(SSPivotException))
            {
                var le = (exception as SSPivotException);
                return (IServiceResultBase)ServiceResult.Fail(le.FriendlyErrorMsg, le.StackTrace);
            }
            else if (typeof(SSPivotException).IsSubclassOf(exception.GetType()))
            {
                var le = (exception as SSPivotException);
                return (IServiceResultBase)ServiceResult.Fail(le.FriendlyErrorMsg, le.StackTrace);
            }
            return (IServiceResultBase)ServiceResult.Fail(exception.Message);
        }
        #endregion
    }
}
